home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 3006 / 3006.xpi / components / dhSmartNamer.js < prev    next >
Text File  |  2010-01-15  |  24KB  |  723 lines

  1. /******************************************************************************
  2.  *            Copyright (c) 2009 Michel Gutierrez. All Rights Reserved.
  3.  ******************************************************************************/
  4.  
  5. /**
  6.  * Constants.
  7.  */
  8.  
  9. const NS_SMARTNAMER_CID = Components.ID("{7d087a1b-d9f1-4698-92ea-b9a1b514ebde}");
  10. const NS_SMARTNAMER_PROG_ID = "@downloadhelper.net/smart-namer;1";
  11. const DHNS = "http://downloadhelper.net/1.0#";
  12.  
  13. var Util=null;
  14.  
  15. /**
  16. * Object constructor
  17. */
  18. function SmartNamer() {
  19.     try {
  20.         //dump("[SmartNamer] constructor\n");
  21.         var prefService=Components.classes["@mozilla.org/preferences-service;1"]
  22.                                            .getService(Components.interfaces.nsIPrefService);
  23.         this.pref=prefService.getBranch("dwhelper.smartnamer.");
  24.         this.observerService = Components.classes["@mozilla.org/observer-service;1"]
  25.                     .getService(Components.interfaces.nsIObserverService);
  26.         this.observerService.addObserver(this,"quit-application",false);
  27.         this.file = Components.classes["@mozilla.org/file/directory_service;1"]
  28.             .getService(Components.interfaces.nsIProperties)
  29.             .get("ProfD", Components.interfaces.nsIFile);
  30.         this.file.append("dh-smart-names.rdf");
  31.         if(!this.file.exists()) {
  32.             var IOS= Components.classes["@mozilla.org/network/io-service;1"]
  33.                                         .getService(Components.interfaces.nsIIOService);
  34.             var channel=IOS.newChannel("chrome://dwhelper/content/smartname.rdf",null,null);
  35.             var input=channel.open();
  36.             var bstream = Components.classes["@mozilla.org/binaryinputstream;1"].
  37.                 createInstance(Components.interfaces.nsIBinaryInputStream);
  38.             bstream.setInputStream(input);
  39.             var bytes = bstream.readBytes(bstream.available());
  40.             input.close();
  41.             var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
  42.                 createInstance(Components.interfaces.nsIFileOutputStream);
  43.             stream.init(this.file, 0x04 | 0x08 | 0x20, 0644, 0); // write, create, truncate
  44.             stream.write(bytes, bytes.length);
  45.             if (stream instanceof Components.interfaces.nsISafeOutputStream) {
  46.                 stream.finish();
  47.             } else {
  48.                 stream.close();
  49.             }
  50.         }
  51.         this.datasource=Util.getDatasourceFromRDFFile(this.file);
  52.     } catch(e) {
  53.         dump("[SmartNamer] !!! constructor: "+e+"\n");
  54.     }
  55. }
  56.  
  57. SmartNamer.prototype = {
  58.         get enabled() { return this.pref.getBoolPref("enabled"); }
  59. }
  60.  
  61. SmartNamer.prototype.updateEntry=function(entry) {
  62.     
  63.     //dump("[SmartNamer] updateEntry()\n");
  64.     if(!this.enabled)
  65.         return;
  66.     var method=Util.getPropsString(entry,"capture-method");
  67.     if(method!="network" && method!="youtube" && method!="youtube-hq" && method!="medialink")
  68.         return;
  69.     var pageUrl=Util.getPropsString(entry,"page-url");
  70.     if(pageUrl==null)
  71.         return;
  72.     var docs=[];
  73.     try {
  74.         var domain=/^https?:\/\/([^\/]+)/.exec(pageUrl)[1];
  75.         var domains=[];
  76.         var parts=domain.split(".");
  77.         for(var i=0;i<parts.length-1;i++) {
  78.             var subdomain=parts.slice(i,parts.length).join(".");
  79.             domains.push(subdomain);
  80.         }
  81.  
  82.         var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]  
  83.                                     .getService(Components.interfaces.nsIWindowMediator);  
  84.         var enumerator = wm.getEnumerator("navigator:browser");  
  85.         while(enumerator.hasMoreElements()) {  
  86.             var win = enumerator.getNext();  
  87.             var tabbrowser = win.getBrowser();
  88.             var numTabs = tabbrowser.browsers.length;
  89.             for(var index=0; index<numTabs; index++) {
  90.                 var currentBrowser = tabbrowser.getBrowserAtIndex(index);
  91.                 var bUrl=currentBrowser.contentDocument.URL;
  92.                 if(bUrl==pageUrl) {
  93.                     docs.push({
  94.                         document: currentBrowser.contentDocument,
  95.                         url: bUrl
  96.                     });
  97.                 }
  98.             }
  99.         }  
  100.     
  101.         var found={}
  102.         var modes=["name","descr"];
  103.         var RDF=Util.getRDF();
  104.         for(var i in docs) {
  105.             var document=docs[i].document;
  106.             for(var j in modes) {
  107.                 var mode=modes[j];
  108.                 if(found[mode]==null) {
  109.                     for(var k in domains) {
  110.                         var domain=domains[k];
  111.                         var l=this.datasource.GetSources(
  112.                                 RDF.GetResource(DHNS+"domain"),
  113.                                 RDF.GetLiteral(domain),
  114.                                 true
  115.                                 );
  116.                         while(l.hasMoreElements()) {
  117.                             var source=l.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  118.                             var srcMode=Util.getPropertyValueRS(this.datasource,source,DHNS+"mode");
  119.                             if(srcMode==mode) {
  120.                                 Util.setPropsString(entry,"sn-domain",domain);
  121.                                 var xpath=Util.getPropertyValueRS(this.datasource,source,DHNS+"xpath");
  122.                                 var text=Util.xpGetString(document.documentElement,xpath);
  123.                                 if(text && text.length>0) {
  124.                                     text=text.replace(/\s{1,}/g,' ');
  125.                                     text=text.replace(/^\s+/,'');
  126.                                     text=text.replace(/\s+$/,'');
  127.                                     var regexp=Util.getPropertyValueRS(this.datasource,source,DHNS+"regexp");
  128.                                     if(regexp.length>0) {
  129.                                         var m=null;
  130.                                         try {
  131.                                             m=new RegExp(regexp).exec(text);
  132.                                             if(m==null || m.length==0)
  133.                                                 text="";
  134.                                             else if(m.length==1)
  135.                                                 text=m[0];
  136.                                             else if(m.length>1)
  137.                                                 text=m[1];
  138.                                             text=text.replace(/^\s+/,'');
  139.                                             text=text.replace(/\s+$/,'');
  140.                                         } catch(e) {}
  141.                                     }
  142.                                     if(text.length>0) {
  143.                                         found[mode]=text;
  144.                                         this.incrStat(source,"xpfound");
  145.                                         if(mode=="name") {
  146.                                             if(Util.getPropsString(entry,"file-name") && Util.getPropsString(entry,"sn-has-org-filename")!="yes") {
  147.                                                 Util.setPropsString(entry,"sn-has-org-filename","yes");
  148.                                                 Util.setPropsString(entry,"sn-org-filename",Util.getPropsString(entry,"file-name"));
  149.                                             }
  150.                                             if(this.pref.getBoolPref("fname.keep-spaces")==false) {
  151.                                                 text=text.replace(/\s+/g,'_');
  152.                                             }
  153.                                             if(this.pref.getBoolPref("fname.keep-nonascii")==false) {
  154.                                                 var fname="";
  155.                                                 for(var n=0;n<text.length;n++) {
  156.                                                     if(text.charCodeAt(n)<128)
  157.                                                         fname=fname+text.charAt(n);
  158.                                                 }
  159.                                                 text=fname;
  160.                                             }
  161.                                             var fname="";
  162.                                             for(var n=0;n<text.length;n++) {
  163.                                                 if(text.charCodeAt(n)>=32)
  164.                                                     fname=fname+text.charAt(n);
  165.                                             }
  166.                                             text=fname;
  167.                                             text=text.replace(/[\/:!\*\?&\|"'\\]/g,'_');
  168.                                             var maxlength=this.pref.getIntPref("fname.maxlen");
  169.                                             var extension=Util.getPropsString(entry,"file-extension");
  170.                                             if(extension) {
  171.                                                 if(text.length+extension.length+1>maxlength)
  172.                                                     text=text.substr(-(maxlength-extension.length-1),maxlength);
  173.                                                 fname=text+"."+extension;
  174.                                             } else {
  175.                                                 fname=text;
  176.                                             }
  177.                                             Util.setPropsString(entry,"file-name",fname);
  178.                                             if(Util.getPropsString(entry,"sn-preserve-label")!="yes") {
  179.                                                 var label=fname;
  180.                                                 if(entry.has("label-prefix")) {
  181.                                                     label=Util.getPropsString(entry,"label-prefix")+label;
  182.                                                 }
  183.                                                 Util.setPropsString(entry,"label",label);
  184.                                             }
  185.                                         }
  186.                                         break;
  187.                                     }
  188.                                 } else {
  189.                                     if(Util.getPropsString(entry,"sn-has-org-filename")=="yes") {
  190.                                         var orgName=Util.getPropsString(entry,"sn-org-filename");
  191.                                         Util.setPropsString(entry,"file-name",orgName);
  192.                                         Util.setPropsString(entry,"label",orgName);
  193.                                     }
  194.                                     this.incrStat(source,"xpnfound");
  195.                                 }
  196.                             }
  197.                         }
  198.                         if(found[mode])
  199.                             break;
  200.                     }
  201.                 }
  202.             }
  203.         }
  204.         for(var i in found) {
  205.             var text=found[i];
  206.             try {
  207.                 var maxLength=this.pref.getIntPref("max."+i);
  208.                 if(maxLength>0 && text.length>maxLength) {
  209.                     text=text.substr(0,maxLength);
  210.                 }
  211.             } catch(e) {}
  212.             Util.setPropsString(entry,"sn-"+i,text);
  213.         }
  214.     } catch(e) {
  215.         dump("!!! [SmartNamer] updateEntry(): "+e+"\n");
  216.     }
  217. }
  218.  
  219. SmartNamer.prototype.incrStat=function(node,stat) {
  220.     var statValue=Util.getPropertyValueRS(this.datasource,node,DHNS+"stat-"+stat);
  221.     if(statValue && parseInt(statValue)!=NaN)
  222.         statValue=parseInt(statValue);
  223.     else
  224.         statValue=0;
  225.     statValue++;
  226.     Util.setPropertyValueRS(this.datasource,node,DHNS+"stat-"+stat,statValue);
  227.     this.mayShare();
  228. }
  229.  
  230. SmartNamer.prototype.incrNameStat=function(entry,stat) {
  231.     //dump("[SmartNamer] incrNameStat(entry,"+stat+")\n");
  232.     if(!this.enabled)
  233.         return;
  234.     var domain=Util.getPropsString(entry,"sn-domain");
  235.     if(domain==null) {
  236.         return;
  237.     }
  238.     var RDF=Util.getRDF();
  239.     var i=this.datasource.GetSources(
  240.             RDF.GetResource(DHNS+"domain"),
  241.             RDF.GetLiteral(domain),
  242.             true
  243.             );
  244.     while(i.hasMoreElements()) {
  245.         var node=i.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  246.         var mode=Util.getPropertyValueRS(this.datasource,node,DHNS+"mode");
  247.         if(mode=="name") {
  248.             this.incrStat(node,stat);
  249.             return;
  250.         }
  251.     }
  252. }
  253.  
  254. SmartNamer.prototype.canHandle=function(document,window,item) {
  255.     //dump("[SmartNamer] canHandle("+document.URL+",window,"+item.tagName+")\n");
  256.     switch(item.id) {
  257.     case "dwhelper-snmenu":
  258.         return this.enabled;
  259.     case "dwhelper-snmenu-set-name":
  260.     case "dwhelper-snmenu-set-descr":
  261.         var range=this.getSelectionRange(window);
  262.         return (range!=null);
  263.     case "dwhelper-snmenu-share-now":
  264.         return this.pref.getBoolPref("manual-share");
  265.     case "dwhelper-snmenu-import":
  266.         return true;
  267.     }
  268.     return false;
  269. }
  270.  
  271. SmartNamer.prototype.handle=function(document,window,item) {
  272.     //dump("[SmartNamer] handle("+document.URL+",window,"+item.tagName+")\n");
  273.     try {
  274.         switch(item.id) {
  275.         case "dwhelper-snmenu-set-name":
  276.         case "dwhelper-snmenu-set-descr":
  277.             var range=this.getSelectionRange(window);
  278.             if(range) {
  279.                 var dialogData={
  280.                     node: range.commonAncestorContainer
  281.                 }
  282.                 if(item.id=="dwhelper-snmenu-set-descr")
  283.                     dialogData.mode="descr";
  284.                 else
  285.                     dialogData.mode="name";
  286.                 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  287.                                             .getService(Components.interfaces.nsIWindowMediator);
  288.                 var w = wm.getMostRecentWindow("navigator:browser");
  289.                 w.openDialog('chrome://dwhelper/content/smart-name-define.xul','dwhelper-dialog',"chrome,centerscreen,modal",dialogData);
  290.                 if(dialogData.ok) {
  291.                     var domain=Util.getPropsString(dialogData.value,"domain");
  292.                     var mode=Util.getPropsString(dialogData.value,"mode");
  293.                     var rdfNode=this.getEntry(domain,mode);
  294.                     this.datasource.beginUpdateBatch();
  295.                     if(rdfNode==null)
  296.                         rdfNode=Util.createAnonymousNodeS(this.datasource,"urn:root");
  297.                     Util.setPropertyValueRS(this.datasource,rdfNode,DHNS+"mode",dialogData.mode);
  298.                     var keys=dialogData.value.getKeys({});
  299.                     for(var i in keys) {
  300.                         var keyValue=Util.getPropsString(dialogData.value,keys[i]);
  301.                         Util.setPropertyValueRS(this.datasource,rdfNode,DHNS+keys[i],keyValue);
  302.                     }
  303.                     Util.setPropertyValueRS(this.datasource,rdfNode,DHNS+"local","1");
  304.                     this.datasource.endUpdateBatch();
  305.                     this.mayShare();
  306.                     this.saveDatasource();
  307.                     this.updateAll();
  308.                 }
  309.             }
  310.             break;
  311.         case "dwhelper-snmenu-share-now":
  312.             this.share();
  313.             break;
  314.         case "dwhelper-snmenu-import":
  315.             this.import();
  316.             break;
  317.         }    
  318.     } catch(e) {
  319.         dump("!!! [SmartNamer] handle("+document.URL+",window,"+item.tagName+"): "+e+"\n");
  320.     }
  321. }
  322.  
  323. SmartNamer.prototype.getSelectionRange=function(window) {
  324.     if(window.document.popupNode==null) 
  325.         return null;
  326.     var seln=window.document.popupNode.ownerDocument.defaultView.getSelection();
  327.     if(seln.rangeCount>0) {
  328.         var range=seln.getRangeAt(0);
  329.         if(!range.collapsed)
  330.             return range;        
  331.     }
  332.     return null;
  333. }
  334.  
  335. SmartNamer.prototype.removeEntry=function(rdfNode) {
  336.     Util.removeReference(this.datasource,rdfNode);
  337.     this.mayShare();
  338.     this.saveDatasource();
  339.     this.updateAll();
  340. }
  341.  
  342. SmartNamer.prototype.share=function() {
  343.     //dump("[SmartNamer] share()\n");
  344.     var props=["domain","xpath","regexp","mode","stat-xpfound","stat-xpnfound","stat-keep","stat-nkeep"];
  345.     var xml=[];
  346.     var haveStats=false;
  347.     xml.push("<?xml version='1.0'?>\n<smartnamer>\n");
  348.     var nodes=Util.getChildResourcesS(this.datasource,"urn:root",{});
  349.     for(var i in nodes) {
  350.         var node=nodes[i];
  351.         //dump("----\n");
  352.         var xml1=[];
  353.         var haveEntryStats=false;
  354.         xml1.push("  <entry");
  355.         for(var j in props) {
  356.             var prop=props[j];
  357.             var value=Util.getPropertyValueRS(this.datasource,node,DHNS+prop);
  358.             if(value) {
  359.                 xml1.push(" "+prop+"='"+Util.xmlEscape(value)+"'");
  360.                 //dump(prop+": "+value+"\n");
  361.                 if(prop.substr(0,5)=="stat-") {
  362.                     if(value!="0") {
  363.                         haveEntryStats=true;
  364.                     }
  365.                     Util.setPropertyValueRS(this.datasource,node,DHNS+prop,"0");
  366.                 }
  367.             }
  368.         }
  369.         xml1.push("/>\n");
  370.         if(haveEntryStats) {
  371.             xml=xml.concat(xml1);
  372.             haveStats=true;
  373.         }
  374.     }
  375.     xml.push("</smartnamer>\n");
  376.     if(haveStats) {
  377.         try {
  378.             var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
  379.                 createInstance(Components.interfaces.nsIXMLHttpRequest);
  380.             xmlhttp.open ("POST", "http://www.downloadhelper.net/share-smartname.php")
  381.             xmlhttp.send(xml.join(""));
  382.         } catch(e) {
  383.             dump("!!! [SmartNamer] share(): "+e+"\n");
  384.         }
  385.     }
  386. }
  387.  
  388. SmartNamer.prototype.import=function() {
  389.     //dump("[SmartNamer] import()\n");
  390.     function StreamListener(service) {
  391.         this.service=service;
  392.     }
  393.  
  394.     StreamListener.prototype={
  395.         QueryInterface: function(iid) {
  396.             if (iid.equals(Components.interfaces.nsISupports) || 
  397.                 iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
  398.                 iid.equals(Components.interfaces.nsIStreamListener)) {
  399.                 return this;
  400.             }
  401.             throw Components.results.NS_ERROR_NO_INTERFACE;
  402.         },
  403.         onStartRequest: function(request,context) {
  404.             this.data="";
  405.         },
  406.         onDataAvailable: function(request,context,inputStream,offset,count) {
  407.             var sstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
  408.                    .createInstance(Components.interfaces.nsIConverterInputStream);
  409.             sstream.init(inputStream, "utf-8", 256, 
  410.                 Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
  411.  
  412.             var str={};
  413.             var n=sstream.readString(128,str);
  414.             while(n>0) {
  415.                 this.data+=str.value;
  416.                 str={};
  417.                 n=sstream.readString(128,str);
  418.             }
  419.         },
  420.         onStopRequest: function(request,context,nsresult) {
  421.             var responseStatus=request.QueryInterface(Components.interfaces.nsIHttpChannel).responseStatus;
  422.             if(responseStatus==200) {
  423.                 this.service.importedData(this.data);
  424.             } else {
  425.                 dump("!!! [SmartNamer] import(): failed download "+responseStatus+"\n");
  426.             }
  427.         },
  428.         getInterface: function(iid) {
  429.             if (iid.equals(Components.interfaces.nsISupports) || 
  430.                 iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
  431.                 iid.equals(Components.interfaces.nsIStreamListener)) {
  432.                 return this;
  433.             }
  434.             return null;
  435.         },
  436.     }
  437.  
  438.     var url="http://www.downloadhelper.net/smartname-data.php";
  439.     var IOS= Components.classes["@mozilla.org/network/io-service;1"]
  440.         .getService(Components.interfaces.nsIIOService);
  441.     var uri = IOS.newURI(url, null, null);
  442.     var channel = IOS.newChannelFromURI(uri);
  443.     var listener = new StreamListener(this);
  444.     channel.notificationCallbacks = listener;
  445.     channel.asyncOpen(listener, null);
  446. }
  447.  
  448. SmartNamer.prototype.importedData=function(data) {
  449.     try {
  450.         //dump("[SmartNamer] importedData():\n"+data+"------\n");
  451.         var datasource=Components.classes
  452.             ['@mozilla.org/rdf/datasource;1?name=in-memory-datasource'].
  453.               createInstance(Components.interfaces.nsIRDFDataSource);
  454.         var parser=Components.classes
  455.             ['@mozilla.org/rdf/xml-parser;1'].
  456.                   createInstance(Components.interfaces.nsIRDFXMLParser);
  457.         var uri = Components.classes["@mozilla.org/network/standard-url;1"].
  458.             createInstance(Components.interfaces.nsIURI);
  459.         uri.spec = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
  460.         parser.parseString(datasource,uri,data);
  461.         
  462.         var RDF=Util.getRDF();
  463.         
  464.         var localNodes=[];
  465.         var changedLocalNodes=[];
  466.         var keepNodes=[];
  467.         var l=this.datasource.GetSources(
  468.                 RDF.GetResource(DHNS+"local"),
  469.                 RDF.GetLiteral("1"),
  470.                 true
  471.                 );
  472.         while(l.hasMoreElements()) {
  473.             var localNode=l.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  474.             var domain=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"domain");            
  475.             var mode=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"mode");            
  476.             var xpath=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"xpath");            
  477.             var regexp=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"regexp");            
  478.             localNodes.push(localNode);
  479.             var found=false;
  480.             var m=datasource.GetSources(
  481.                     RDF.GetResource(DHNS+"domain"),
  482.                     RDF.GetLiteral(domain),
  483.                     true
  484.                     );
  485.             while(m.hasMoreElements()) {
  486.                 var node=m.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  487.                 var mode0=Util.getPropertyValueRS(datasource,node,DHNS+"mode");
  488.                 var xpath0=Util.getPropertyValueRS(datasource,node,DHNS+"xpath");
  489.                 var regexp0=Util.getPropertyValueRS(datasource,node,DHNS+"regexp");
  490.                 if(mode==mode0) {
  491.                     found=true;
  492.                     if(xpath!=xpath0 || regexp!=regexp0) {
  493.                         changedLocalNodes.push(localNode);
  494.                     }
  495.                 }
  496.             }
  497.             if(found==false) {
  498.                 keepNodes.push(localNode);
  499.             }
  500.         }
  501.                 
  502.         for(var i in changedLocalNodes) {
  503.             var localNode=changedLocalNodes[i];
  504.             var domain=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"domain");            
  505.             var mode=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"mode");            
  506.             var xpath=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"xpath");            
  507.             var regexp=Util.getPropertyValueRS(this.datasource,localNode,DHNS+"regexp");            
  508.         }
  509.         
  510.         if(changedLocalNodes.length>0) {
  511.             var dialogData={
  512.                 overlap: changedLocalNodes
  513.             };
  514.             var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  515.                                         .getService(Components.interfaces.nsIWindowMediator);
  516.             var w = wm.getMostRecentWindow("navigator:browser");
  517.             w.openDialog('chrome://dwhelper/content/smart-name-overlap.xul','dwhelper-dialog',"chrome,centerscreen,modal",dialogData);
  518.             if(!dialogData.ok)
  519.                 return;
  520.             keepNodes=keepNodes.concat(dialogData.value);
  521.         }
  522.         
  523.         var props=["domain","mode","xpath","regexp","local","stat-xpfound","stat-xpnfound","stat-keep","stat-nkeep"];
  524.         for(var i in keepNodes) {
  525.             var node=keepNodes[i];
  526.             var domain=Util.getPropertyValueRS(this.datasource,node,DHNS+"domain");            
  527.             var mode=Util.getPropertyValueRS(this.datasource,node,DHNS+"mode");
  528.             Util.removeReferenceS(datasource,DHNS+domain+"/"+mode);
  529.             var node0=Util.createAnonymousNodeS(datasource,"urn:root");
  530.             for(var j in props) {
  531.                 var prop=props[j];
  532.                 var value=Util.getPropertyValueRS(this.datasource,node,DHNS+prop);
  533.                 if(value) {
  534.                     Util.setPropertyValueRS(datasource,node0,DHNS+prop,value);
  535.                 }
  536.             }
  537.         }
  538.         Util.emptyDatasource(this.datasource);
  539.         Util.concatDatasource(this.datasource,datasource);
  540.         this.saveDatasource();
  541.         this.updateAll();
  542.     } catch(e) {
  543.         dump("!!! [SmartNamer] importedData(): "+e+"\n");
  544.     }
  545. }
  546.  
  547. SmartNamer.prototype.getEntry=function(domain,mode) {
  548.     try {
  549.     var RDF=Util.getRDF();
  550.     var i=this.datasource.GetSources(
  551.             RDF.GetResource(DHNS+"domain"),
  552.             RDF.GetLiteral(domain),
  553.             true
  554.             );
  555.     while(i.hasMoreElements()) {
  556.         var source=i.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  557.         var srcMode=Util.getPropertyValueRS(this.datasource,source,DHNS+"mode");
  558.         if(srcMode==mode)
  559.             return source;
  560.     }
  561.     return null;
  562.     
  563.     } catch(e) {
  564.         dump("!!! [SmartNamer] getEntry("+domain+","+mode+"): "+e+"\n");
  565.     }
  566. }
  567.  
  568. SmartNamer.prototype.mayShare=function() {
  569.     //dump("[SmartNamer] mayShare()\n");
  570.     
  571.     if(this.pref.getBoolPref("auto-share")==false)
  572.         return;
  573.     var now=new Date().getTime()/1000;
  574.     try {
  575.         var last=this.pref.getIntPref("last-shared");
  576.         if(now-last>(60*60*24)) { // once a day
  577.             this.share();
  578.             this.pref.setIntPref("last-shared",now);
  579.         }
  580.     } catch(e) {
  581.         this.pref.setIntPref("last-shared",now);
  582.     }
  583. }
  584.  
  585. SmartNamer.prototype.observe=function(subject,topic,data) {
  586.     if(topic=="quit-application") {
  587.         this.mayShare();
  588.         this.saveDatasource();
  589.         this.observerService.removeObserver(this,"quit-application");
  590.     }
  591. }
  592.  
  593. SmartNamer.prototype.saveDatasource=function() {
  594.     //dump("[SmartNamer] saveDatasource()\n");
  595.     try {
  596.         var serializer="@mozilla.org/rdf/xml-serializer;1";
  597.         var s=Components.classes[serializer].createInstance(Components.interfaces.nsIRDFXMLSerializer);
  598.         s.init(this.datasource);
  599.         var stream = Components.classes['@mozilla.org/network/file-output-stream;1']
  600.             .createInstance(Components.interfaces.nsIFileOutputStream);
  601.         stream.init(this.file, 42, 0644, 0); 
  602.     
  603.         s.QueryInterface(Components.interfaces.nsIRDFXMLSource).Serialize(stream);
  604.         stream.close();
  605.     } catch(e) {
  606.         dump("!!! [SmartNamer] saveDatasource: "+e+"\n");
  607.     }
  608. }
  609.  
  610. SmartNamer.prototype.getDatasource=function() {
  611.     //dump("[SmartNamer] getDatasource()\n");
  612.     return this.datasource;
  613. }
  614.  
  615. SmartNamer.prototype.updateAll=function() {
  616.     if(this.core==null)
  617.         this.core=Components.classes["@downloadhelper.net/core;1"].
  618.             getService(Components.interfaces.dhICore);
  619.     this.core.updateSmartName();
  620. }
  621.  
  622. SmartNamer.prototype.QueryInterface = function(iid) {
  623.     //dump("[SmartNamer] QueryInterface("+iid+")\n");
  624.     if(
  625.         iid.equals(Components.interfaces.dhISmartNamer) ||
  626.         iid.equals(Components.interfaces.nsIObserver) ||
  627.         iid.equals(Components.interfaces.dhIContextItem) ||
  628.         iid.equals(Components.interfaces.nsISupports)
  629.     ) {
  630.         return this;
  631.     }
  632.     throw Components.results.NS_ERROR_NO_INTERFACE;
  633. }
  634.  
  635. var vSmartNamerModule = {
  636.     firstTime: true,
  637.     
  638.     /*
  639.      * RegisterSelf is called at registration time (component installation
  640.      * or the only-until-release startup autoregistration) and is responsible
  641.      * for notifying the component manager of all components implemented in
  642.      * this module.  The fileSpec, location and type parameters are mostly
  643.      * opaque, and should be passed on to the registerComponent call
  644.      * unmolested.
  645.      */
  646.     registerSelf: function (compMgr, fileSpec, location, type) {
  647.  
  648.         if (this.firstTime) {
  649.             this.firstTime = false;
  650.             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  651.         }
  652.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  653.         compMgr.registerFactoryLocation(NS_SMARTNAMER_CID,
  654.                                         "SmartNamer",
  655.                                         NS_SMARTNAMER_PROG_ID, 
  656.                                         fileSpec,
  657.                                         location,
  658.                                         type);
  659.     },
  660.  
  661.     unregisterSelf: function(compMgr, fileSpec, location) {
  662.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  663.         compMgr.unregisterFactoryLocation(NS_DH_SMARTNAMER_CID, fileSpec);
  664.     },
  665.  
  666.     /*
  667.      * The GetClassObject method is responsible for producing Factory and
  668.      * SingletonFactory objects (the latter are specialized for services).
  669.      */
  670.     getClassObject: function (compMgr, cid, iid) {
  671.         if (!cid.equals(NS_SMARTNAMER_CID)) {
  672.             throw Components.results.NS_ERROR_NO_INTERFACE;
  673.         }
  674.  
  675.         if (!iid.equals(Components.interfaces.nsIFactory)) {
  676.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  677.         }
  678.  
  679.         return this.vSmartNamerFactory;
  680.     },
  681.  
  682.     /* factory object */
  683.     vSmartNamerFactory: {
  684.         /*
  685.          * Construct an instance of the interface specified by iid, possibly
  686.          * aggregating it with the provided outer.  (If you don't know what
  687.          * aggregation is all about, you don't need to.  It reduces even the
  688.          * mightiest of XPCOM warriors to snivelling cowards.)
  689.          */
  690.         createInstance: function (outer, iid) {
  691.             if (outer != null) {
  692.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  693.             }
  694.     
  695.             if(Util==null) 
  696.                 Util=Components.classes["@downloadhelper.net/util-service;1"]
  697.                     .getService(Components.interfaces.dhIUtilService);
  698.  
  699.             return new SmartNamer().QueryInterface(iid);
  700.         }
  701.     },
  702.  
  703.     /*
  704.      * The canUnload method signals that the component is about to be unloaded.
  705.      * C++ components can return false to indicate that they don't wish to be
  706.      * unloaded, but the return value from JS components' canUnload is ignored:
  707.      * mark-and-sweep will keep everything around until it's no longer in use,
  708.      * making unconditional ``unload'' safe.
  709.      *
  710.      * You still need to provide a (likely useless) canUnload method, though:
  711.      * it's part of the nsIModule interface contract, and the JS loader _will_
  712.      * call it.
  713.      */
  714.     canUnload: function(compMgr) {
  715.         return true;
  716.     }
  717. };
  718.  
  719. function NSGetModule(compMgr, fileSpec) {
  720.     return vSmartNamerModule;
  721. }
  722.  
  723.